import io, re, string
from collections import deque
import Global,Semantics

matrixPath = './Matrix.txt'
reductionPath = './Reduction.txt'
flag_insert = 0

matrix = []
reductions = []

def pushStack():
    Global.syntax_stack.append(Global.lexical_queue.popleft())
    Global.symbol_stack.append(Global.symbol_queue.popleft())
    Global.semantics_stack.append(Global.semantics_queue.popleft())

def popStack():
    Global.syntax_stack.pop()
    Global.symbol_stack.pop()
    Global.semantics_stack.pop()

def importMatrix():
    matrixFile = file(matrixPath, 'r')
    for line in matrixFile:
        matrix.append(re.findall('\d',line))
    matrixFile.close()

def importReductions():
    reductionFile = file(reductionPath, 'r')
    temp_reductions = []
    for line in reductionFile:
        temp_reductions.append(line.split())
    reductionFile.close()

    for i in range(len(temp_reductions)):
        temp = []
        for j in range(len(temp_reductions[i])):
             temp.append(int(temp_reductions[i][j]))
        reductions.append(temp)

def matchLongest():
    def munge(s):
        return ", "+format(str(s)[1:-1])+","
    count = 0
    l_reduction = []
    for reduction in reductions:
        if munge(reduction[1:-1]) in munge(Global.syntax_stack) and count<reduction[0]:
            flag = 0;
            for i in range(len(reduction[1:-1])):
                if reduction[0-(i+2)] != Global.syntax_stack[0-(i+1)]:
                    flag = 1
                    break
            if flag == 0:
                count = reduction[0]
                l_reduction = reduction
    return l_reduction

def printReduction(reduction):
    if Global.flag[7] == 1:
        s = 'Reduction #'+str(reductions.index(reduction)+1)+': '+Global.tokens.keys()[Global.tokens.values().index(reduction[-1])]
        s += ' -->'
        for code in reduction[1:-1]:
            s = s+' '+Global.tokens.keys()[Global.tokens.values().index(code)]+' '
        Global.outputFile.write(5*'	'+s+'\n')

def printStack():
    if Global.flag[8] == 1:
        Global.outputFile.write('The stack now: ')
        for i in range(len(Global.syntax_stack[1::])):
            Global.outputFile.write(Global.symbol_stack[i]+' | ')
        Global.outputFile.write('\n')

def printRelation():
    if Global.flag[9] == 1:
        Global.outputFile.write('The top of the stack is: ')
        Global.outputFile.write(Global.symbol_stack[-1])
        Global.outputFile.write(', The input symbol is: ')
        Global.outputFile.write(Global.symbol_queue[0])
        Global.outputFile.write(', The relation is: ')
        if matrix[Global.syntax_stack[-1]-1][Global.lexical_queue[0]-1] == '2':
            Global.outputFile.write('greater than\n')
        elif matrix[Global.syntax_stack[-1]-1][Global.lexical_queue[0]-1] == '0':
            Global.outputFile.write('no relation\n')
        elif matrix[Global.syntax_stack[-1]-1][Global.lexical_queue[0]-1] == '1':
            Global.outputFile.write('equal\n')
        else:
            Global.outputFile.write('less than\n')

def printHandle(reduction):
    if Global.flag[10] == 1:
        Global.outputFile.write('The matched handle is: ')
        for code in reduction:
            Global.outputFile.write(Global.tokens.keys()[Global.tokens.values().index(code)]+' ')
        Global.outputFile.write('\n')

def ajustStack(reduction):
#    print "Before " + str(Global.semantics_stack)
    Semantics.printSemanticsStack()
    location = Semantics.insertSymbolTable(reductions, reduction)
    for i in range(len(reduction[1:-1])):
        popStack()
        if flag_insert == 0:
            Global.count_syntax_stack -= 1
    Global.syntax_stack.append(reduction[-1])
    Global.symbol_stack.append(Global.tokens.keys()[Global.tokens.values().index(reduction[-1])])
    Global.semantics_stack.append(location)
    if flag_insert == 0:
        Global.count_syntax_stack += 1
    Semantics.printSemanticsStack()
#    print "After " + str(Global.semantics_stack)


def errorHandle():
    e_stack = Global.symbol_stack[-1]
    e_queue = Global.symbol_queue[0]
    Global.outputFile.write('Character Pair Error in line '+str(Global.count_line)+' between '+e_stack+' and '+e_queue+'\n')
    Global.outputFile.write('Symbols ignored from the input statement: ')
    while Global.lexical_queue != deque([]):
        Global.lexical_queue.popleft()
        Global.outputFile.write(Global.symbol_queue.popleft()+' ')
    Global.outputFile.write('\nSymbols popped from the stack: ')
    for i in range(Global.count_syntax_stack):
        Global.syntax_stack.pop()
        Global.outputFile.write(Global.symbol_stack.pop()+' ')
    Global.outputFile.write('\nStack is: ')
    for i in range(len(Global.syntax_stack[1::])):
        Global.outputFile.write(Global.symbol_stack[i]+' | ')
    Global.outputFile.write('\n')

def reduction():
    printRelation()
    reduction = matchLongest()
    printHandle(reduction[1:-1])
    printStack()
    ajustStack(reduction)
    printReduction(reduction)
    #printStack()

def parser():
    global flag_insert
    importMatrix()
    importReductions()
    while Global.lexical_queue != deque([]):
        if Global.syntax_stack[-1] == 0:
            pushStack()
            Global.count_syntax_stack += 1
        elif matrix[Global.syntax_stack[-1]-1][Global.lexical_queue[0]-1] == '2':
            reduction()
        elif matrix[Global.syntax_stack[-1]-1][Global.lexical_queue[0]-1] == '0':
            printRelation()
            errorHandle()
        else:
            printRelation()
            pushStack()
            Global.count_syntax_stack += 1
            flag_insert = 1
    Global.count_syntax_stack = 0
